package models.users

import play.api.Logging

import java.sql.Timestamp
import javax.inject.{Inject, Singleton}
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import slick.jdbc.JdbcProfile

import java.time.LocalDateTime
import javax.swing.UIDefaults.ActiveValue
import scala.concurrent.{ExecutionContext, Future}

@Singleton
class UserGroupRepository @Inject()(protected val dbConfigProvider: DatabaseConfigProvider)(implicit executionContext: ExecutionContext)
  extends HasDatabaseConfigProvider[JdbcProfile] with Logging {

  import profile.api._

  protected class UserGroupTable(tag: Tag) extends Table[UserGroup](tag, "BASE_USER_GROUP".toUpperCase) {
    def id = column[Long]("id".toUpperCase, O.PrimaryKey)

    def uid = column[Int]("uid_id".toUpperCase)

    def gid = column[Long]("gid_id".toUpperCase)

    def * = (id, uid, gid).<>((UserGroup.apply _).tupled, UserGroup.unapply)
  }

  private[users] val ugTable = TableQuery[UserGroupTable]

  protected class GroupTable(tag: Tag) extends Table[Group](tag, "BASE_GROUPS") {
    def id = column[Long]("id".toUpperCase, O.PrimaryKey)

    def parentid = column[Long]("parentid".toUpperCase)

    def pname = column[String]("pname".toUpperCase)

    def company = column[Int]("company".toUpperCase)

    def nas_gid = column[Int]("nasgroup_id".toUpperCase)

    def * = (id, parentid, pname, company, nas_gid).<>((Group.apply _).tupled, Group.unapply)
  }

  private[models] val groupTable = TableQuery[GroupTable]


  protected class AccountTable(tag: Tag) extends Table[Account](tag, "BASE_USERS") {
    def id = column[Option[Int]]("id".toUpperCase, O.PrimaryKey, O.AutoInc)

    def password = column[String]("password".toUpperCase)

    def username = column[String]("username".toUpperCase)

    def position = column[Option[String]]("position".toUpperCase)

    def is_active = column[Int]("PERMISSION")

    def userid = column[String]("userid".toUpperCase)

    def unionid = column[String]("unionid".toUpperCase)

    def mobile = column[String]("mobile".toUpperCase)

    def avatar = column[Option[String]]("avatar".toUpperCase)

    def lastLoginDate = column[Option[Timestamp]]("last_Login_Date".toUpperCase)

    def op_date = column[Timestamp]("op_date".toUpperCase)

    def * = (id, password, username, position, is_active, userid, unionid,
      mobile, avatar, lastLoginDate, op_date).<>((Account.apply _).tupled, Account.unapply)
  }

  private[models] val accountTable = TableQuery[AccountTable]

  protected class UserInfoTable(tag: Tag) extends Table[UserInfo](tag, "BASE_USER_INFO") {
    def id = column[Option[Int]]("id".toUpperCase, O.PrimaryKey, O.AutoInc)

    def accountId = column[Int]("uid_id".toUpperCase)

    def company = column[Int]("company".toUpperCase)

    def is_active = column[Int]("is_active".toUpperCase)

    def username = column[String]("username".toUpperCase)

    def position = column[Option[String]]("position".toUpperCase)

    def email = column[Option[String]]("email".toUpperCase)

    def userid = column[String]("userid".toUpperCase)

    def unionid = column[String]("unionid".toUpperCase)

    def tel = column[Option[String]]("tel".toUpperCase)

    def workPlace = column[Option[String]]("workPlace".toUpperCase)

    def remark = column[Option[String]]("remark".toUpperCase)

    def mobile = column[String]("mobile".toUpperCase)

    def orgEmail = column[Option[String]]("orgEmail".toUpperCase)

    def isLeaderInDepts = column[Option[String]]("isLeaderInDepts".toUpperCase)

    def department = column[String]("department".toUpperCase)

    def avatar = column[Option[String]]("avatar".toUpperCase)

    def hiredDate = column[Timestamp]("hiredDate".toUpperCase)

    def jobnumber = column[Option[String]]("jobnumber".toUpperCase)

    def extattr = column[Option[String]]("extattr".toUpperCase)

    def leaveDate = column[Option[Timestamp]]("leaveDate".toUpperCase)

    def op_date = column[Timestamp]("op_date".toUpperCase)

    def * = (id, accountId, company, is_active, username, position, email, userid, unionid, tel,
      workPlace, remark, mobile, orgEmail, isLeaderInDepts, department, avatar, hiredDate,
      jobnumber, extattr, leaveDate,op_date).<>((UserInfo.apply _).tupled, UserInfo.unapply)
  }

  private[models] val userInfoTable = TableQuery[UserInfoTable]

  protected class AppNasGroupTable(tag: Tag) extends Table[NasGroup](tag, "SYS_NAS_Group".toUpperCase) {
    def id = column[Option[Int]]("id".toUpperCase, O.PrimaryKey, O.AutoInc)

    def app_group_id = column[Int]("app_group_id".toUpperCase)

    def pname = column[String]("pname".toUpperCase)

    def app_group_name = column[String]("app_group_name".toUpperCase)

    def checked = column[Boolean]("checked".toUpperCase)

    def * = (id, app_group_id, app_group_name, pname, checked)
      .<>((NasGroup.apply _).tupled, NasGroup.unapply)
  }

  private[models] val nasGroupTable = TableQuery[AppNasGroupTable]

  protected class AppNasUserTable(tag: Tag) extends Table[NasUser](tag, "SYS_NAS_User".toUpperCase) {
    def id = column[Int]("id".toUpperCase, O.PrimaryKey)

    def app_user_id = column[Int]("app_user_id".toUpperCase)

    def app_user_name = column[String]("app_user_name".toUpperCase)

    def locked = column[Boolean]("status".toUpperCase)

    def group_id = column[Int]("group_id".toUpperCase)

    def checked = column[Boolean]("checked".toUpperCase)

    def * = (id, app_user_id, app_user_name, locked, group_id, checked)
      .<>((NasUser.apply _).tupled, NasUser.unapply)
  }

  private[models] val nasUserTable = TableQuery[AppNasUserTable]

  /////////////////////////////////////

  def userFindBy(id: Option[Int] = None,
                 //                 userid: String = "",
                 //                 unionid: String = "",
                 mobile: String = "",
                 is_active: Option[Int] = None
                ) = db.run {
    accountTable
      .filterOpt(id)(_.id === _)
      //      .filterIf(userid != "")(_.userid === userid)
      //      .filterIf(unionid != "")(_.unionid === unionid)
      .filterIf(mobile != "")(_.mobile === mobile)
      .filterOpt(is_active)(_.is_active === _)
      .map(f => f).result
  }

  //  def userFindAllSimple = db.run {
  //    accountTable.filter(_.id > 1).map(f => (f.userid, f.is_active)).result
  //  }

  def getUserInfoSimple(compang: Int) = db.run {
    userInfoTable.filter(_.company === compang)
      .map(f => (f.company, f.userid, f.is_active, f.unionid, f.id)).result
  }

  private def accountupdate(account: Account) = db.run {
    accountTable.filter(_.id === account.id).map(user => (
      user.username,
      user.position,
      user.mobile,
      user.avatar
    )).update((
      account.username,
      account.position,
      account.mobile,
      account.avatar
    ))
  }

  private def accountCreate(account: Account) = {
    logger.debug(s"$account")
    db.run {
      accountTable.filter(_.mobile === account.mobile).map(f => f).result
    }.flatMap { r =>
      logger.debug(s"accountCreate find account = ${r.mkString(",")}")
      if (r.isEmpty) {
        db.run {
          (accountTable returning accountTable.map(_.id)) += account
        }
      }
      else Future(r.head.id)
    }
  }

  private def userCreate(uid: Int, user: User) = {
    val userInfo = UserInfo(
      accountId = uid,
      company = user.company,
      is_active = activeValue,
      username = user.username,
      position = user.position,
      email = user.email,
      userid = user.userid,
      unionid = user.unionid,
      tel = user.tel,
      workPlace = user.workPlace,
      remark = user.remark,
      mobile = user.mobile,
      orgEmail = user.orgEmail,
      isLeaderInDepts = user.isLeaderInDepts,
      department = user.department,
      avatar = user.avatar,
      hiredDate = user.hiredDate,
      jobnumber = user.jobnumber,
      extattr = user.extattr
    )
    logger.debug(s"userCreate userInfo = $userInfo")
    db.run {
      //      (userInfoTable returning userInfoTable.map(_.id)) += userInfo
      userInfoTable += userInfo
    }
  }

  private def userUpdate(id: Option[Int], user: User) = {
    logger.debug(s"userUpdate userInfo = $user")
    db.run {
      userInfoTable.filter(_.id === id)
        .map(u => (
          u.username,
          u.position,
          u.email,
          u.tel,
          u.workPlace,
          u.remark,
          u.mobile,
          u.orgEmail,
          u.isLeaderInDepts,
          u.department,
          u.avatar,
          u.hiredDate,
          u.jobnumber,
          u.extattr,
          u.is_active,
          u.userid,
          u.op_date
        ))
        .update((
          user.username,
          user.position,
          user.email,
          user.tel,
          user.workPlace,
          user.remark,
          user.mobile,
          user.orgEmail,
          user.isLeaderInDepts,
          user.department,
          user.avatar,
          user.hiredDate,
          user.jobnumber,
          user.extattr,
          activeValue,
          user.userid,
          Timestamp.valueOf(LocalDateTime.now())
        ))
    }
  }

  val activeValue = 10

  def userCreateUpdate(user: User) = {

    db.run {
      userInfoTable.filter(_.unionid === user.unionid).filter(_.company === user.company).map(f => f).result
    }.flatMap {
      userInfo => {
        logger.debug(s"userCreateUpdate find userInfo = ${userInfo.mkString(",")}")
        if (userInfo.isEmpty) {
          val account = Account(
            password = user.password, //
            username = user.username, //  手机号码hash
            position = user.position, //  职位信息
            permission = 1, //
            userid = user.userid, //  员工在当前企业内的唯一标识，也称staffId。可由企业在创建时指定，并代表一定含义比如工号，创建后不可修改
            unionid = user.unionid, //  员工在当前开发者企业账号范围内的唯一标识，系统生成，固定值，不会改变
            mobile = user.mobile, //  手机号码
            avatar = user.avatar //  头像url
          )
          // account create
          accountCreate(account).flatMap { uid => {
            userCreate(uid.getOrElse(0), user)
          }
          }
        } else {
          logger.debug("userInfo.nonEmpty")
          val account = Account(
            id = Some(userInfo.head.accountId),
            password = user.password, //
            username = user.username, //  手机号码hash
            position = user.position, //  职位信息
            permission = 1, //
            userid = user.userid, //  员工在当前企业内的唯一标识，也称staffId。可由企业在创建时指定，并代表一定含义比如工号，创建后不可修改
            unionid = user.unionid, //  员工在当前开发者企业账号范围内的唯一标识，系统生成，固定值，不会改变
            mobile = user.mobile, //  手机号码
            avatar = user.avatar //  头像url
          )
          accountupdate(account).flatMap(result => userUpdate(userInfo.head.id, user))
        }
      }
    }
  }

  //  def userUpdate(user: User) = db.run {
  //    userTable.filter(_.unionid === user.unionid).map(f => f).update(user)
  //  }

  def userActiveFalseTest(userid: String) = db.run {
    val this_id = userInfoTable.filter(_.userid === userid)
    val q = userInfoTable.filter(_.accountId in this_id.map(_.accountId)).map(f => f.is_active)
    val q3 = q.sum
    println(q3.shaped.result.statements.head)
    q3.result
  }

  def userActiveFalse(company: Int, userid: String, activeValue: Int) = {
    lazy val this_id = userInfoTable.filter(_.userid === userid).filter(_.company === company)
    if (activeValue >= 1) {
      val leaveDate = if (activeValue == 1) Some(Timestamp.valueOf(LocalDateTime.now())) else None
      db.run {
        userInfoTable
          .filter(_.userid === userid)
          .filter(_.company === company)
          .map(f => (f.is_active, f.leaveDate,f.op_date))
          .update((activeValue - 1, leaveDate,Timestamp.valueOf(LocalDateTime.now())))
      }
    } else {
      db.run {
        userInfoTable.filter(_.userid === userid).filter(_.company === company).map(f => (f.is_active)).update(0)
      }
      db.run(ugTable.filter(_.uid in this_id.map(_.id)).delete)
    }
  }

  def userActiveFalse1(company: Int, userid: String, activeValue: Int) = db.run {
    userInfoTable.filter(_.userid === userid).filter(_.company === company).map(f => f).result
  }.flatMap { user =>
    val active = if (user.nonEmpty) {
      user.head.is_active
    } else 0
    if (active == 1) {
      db.run {
        userInfoTable
          .filter(_.userid === userid)
          .filter(_.company === company)
          .map(f => (f.is_active, f.leaveDate,f.op_date))
          .update(0, Some(Timestamp.valueOf(LocalDateTime.now())),Timestamp.valueOf(LocalDateTime.now()))
      }
    } else if (active == 0) {
      lazy val this_id = userInfoTable.filter(_.userid === userid).filter(_.company === company)
      db.run(ugTable.filter(_.uid in this_id.map(_.id)).delete)
    } else {
      db.run {
        userInfoTable.filter(_.userid === userid)
          .filter(_.company === company)
          .map(f => (f.is_active,f.op_date))
          .update(active - 1,Timestamp.valueOf(LocalDateTime.now()))
      }
    }
  }

  def userInfoActive(company: Int, userid: String) = db.run {
    userInfoTable.filter(_.userid === userid)
      .filter(_.company === company)
      .map(f => (f.is_active,f.op_date))
      .update((activeValue,Timestamp.valueOf(LocalDateTime.now())))
  }

//  def accountActiveFalse() = {
//    db.run {
//      userInfoTable
//        .map(f => f)
//        .groupBy(_.accountId)
//        .map(f =>
//          (f._1, f._2.map(a => a.is_active).sum)
//        )
//        .result
//    }.map {
//      res =>
//        res.map {
//          user =>
//            db.run {
//              if (user._2.getOrElse(0) == 0 && user._1 != 1) {
//                accountTable.filter(_.id === user._1)
//                  .filter(_.is_active =!= 0)
//                  .map(f => (f.is_active,f.op_date))
//                  .update((0,Timestamp.valueOf(LocalDateTime.now())))
//              } else {
//                accountTable.filter(_.id === user._1)
//                  .filter(_.is_active === 0)
//                  .map(f => (f.is_active,f.op_date))
//                  .update((1,Timestamp.valueOf(LocalDateTime.now())))
//              }
//            }
//        }
//    }
//  }

  def accountSetPermission() = {
    db.run {
      // 全组织
      userInfoTable
        .filter(_.is_active =!= 0)
        .groupBy(_.accountId)
        .map(f =>
          (f._1, f._2.map(a => a.is_active).size)
        ).filter(_._2 > 1).map(f => f._1).result
    }.flatMap {
      userinfo => {
        db.run {
          accountTable
            .filter(_.is_active =!= 2)
            .filter(_.id inSet (userinfo))
            .map(f => f.is_active).update(2) // 参见 PermissionAccess.access_permissions
        }
      }
    }
    db.run {
      // 五羊
      userInfoTable
        .filter(_.is_active =!= 0)
        .filter(_.company === 101)
        .map(f => f.accountId).result
    }.flatMap { userinfo =>
      db.run {
        accountTable
          .filter(_.is_active =!= 2)
          .filter(_.is_active =!= 3)
          .filter(_.id inSet (userinfo))
          .map(f => f.is_active).update(3) // 参见 PermissionAccess.access_permissions
      }
    }
    db.run {
      // 礼顿
      userInfoTable
        .filter(_.is_active =!= 0)
        .filter(_.company === 201)
        .map(f => f.accountId).result
    }.flatMap { userinfo =>
      db.run {
        accountTable
          .filter(_.is_active =!= 2)
          .filter(_.is_active =!= 4)
          .filter(_.id inSet (userinfo))
          .map(f => f.is_active).update(4) // 参见 PermissionAccess.access_permissions
      }
    }
    db.run {
      // 礼顿
      userInfoTable
        .filter(_.is_active =!= 0)
        .filter(_.company === 104)
        .map(f => f.accountId).result
    }.flatMap { userinfo =>
      db.run {
        accountTable
          .filter(_.is_active =!= 2)
          .filter(_.is_active =!= 5)
          .filter(_.id inSet (userinfo))
          .map(f => f.is_active).update(5) // 参见 PermissionAccess.access_permissions
      }
    }
  }


  def userFindByNamePwd(id:Int=0,unionid: String = "", mobile: String = "", userid: String = "") = {
    lazy val userFind = (m: String) => db.run {
      accountTable
        .filter(_.mobile === m)
        //.filter(_.is_active === true)
        .map(f => f)
        .result
    }
    if (id !=0 ) db.run{
      accountTable
        .filter(_.id === id)
        //.filter(_.is_active === true)
        .map(f => f)
        .result
    }else if (mobile == "") {
      db.run {
        userInfoTable
          .filterIf(unionid != "")(_.unionid === unionid)
          .filterIf(userid != "")(_.userid === userid)
          //.filter(_.is_active > 0)
          .map(f => f)
          .result
      }.flatMap { user =>
        if (user.isEmpty) userFind("")
        else userFind(user.head.mobile)
      }
    }
    else userFind(mobile)
  }


  def userUpdatePassword(accId: Int, password: String) = db.run {
    accountTable.filter(_.id === accId).map(f => f.password).update(password)
  }

  def userUpdateLastLoginDate(id: Option[Int] = None, ld: Option[Timestamp] = None) = db.run {
    accountTable.filter(_.id === id).map(f => f.lastLoginDate).update(ld)
  }

  def groupCreate(group: Group) = db.run(groupTable.filter(_.id === group.id).result).flatMap {
    f =>
      db.run(
        if (f.nonEmpty) groupTable.filter(_.id === group.id).map(f => (f.parentid, f.pname)).update((group.parentid, group.pname))
        else groupTable += group
      )
  }

  def groupDelete(id: Long) = {
    db.run(groupTable.filter(_.id === id).delete)
    db.run(ugTable.filter(_.gid === id).delete)
  }


  def ugRelationCreate(ug: UserGroup) = db.run {
    //    ugTable.filter(f => List(f.uid === ug.uid, f.gid === ug.gid).reduce(_ && _)).result
    ugTable.filter(_.id === ug.id).result
  }.flatMap {
    f => if (f.nonEmpty) Future(f.head.id) else db.run(ugTable += ug)
  }

  def ugRelationDelete(uid: Option[Int] = None, gid: Option[Long] = None) = db.run {
    ugTable.filterOpt(uid)(_.uid === _).filterOpt(gid)(_.gid === _).delete
  }

  def ugRelationFind = db.run(ugTable.map(f => f).result)

  def userResUID(userid: String) = db.run(accountTable.filter(_.userid === userid).map(_.id).result)


}
